package com.ruoyi.common.utils.bean;

import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.ruoyi.common.core.domain.BaseEntity;
import com.ruoyi.common.core.domain.Select;
import com.ruoyi.common.exception.InteriorException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.reflect.ReflectUtils;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.*;
import java.util.function.Function;

/**
 * @Classname SelectUtils
 * @Author: sunluquan
 * @Date: 2021/12/29 13:40
 * @Description TODO
 * 选择器的工具类
 */
public class SelectUtils {

    /**
     * 构建selectList 供前端 select选择器统一使用
     * @param sources 源对象
     * @param tiSelectFunction 转换器
     * @param <T>
     * @return 转换后的 List<ISelect>集合
     */
    public static <T> List<Select> buildSelectList(Collection<T> sources, Function<T, Select> tiSelectFunction){

        List<Select> selectList = new ArrayList<>();

        if(StringUtils.isNotEmpty(sources)){

            sources.forEach( source -> selectList.add(tiSelectFunction.apply(source)));

        }

        return selectList;
    }

    /**
     * 构建selectList 供前端 select选择器统一使用
     * @param sources 源对象集合
     * @param valueSFunction value属性
     * @param labelSFunction lable属性
     * @param fill 默认为false 不填充data true填充data
     * @param <T>
     * @return
     */
    public static <T> List<Select> buildSelectList(Collection<T> sources, SFunction<T,? extends Serializable> valueSFunction, SFunction<T,? extends Serializable> labelSFunction,boolean fill){

        List<Select> selectList = new ArrayList<>();

        if(StringUtils.isNotEmpty(sources)){

            boolean sort = false;

            String valueFieldName = ReflectionUtil.getFieldName(valueSFunction);
            String labelFieldName = valueSFunction == labelSFunction?valueFieldName:ReflectionUtil.getFieldName(labelSFunction);

            Map<String, PropertyDescriptor> propertyDescriptorMap = BeanUtils.getPropertyDescriptorMap(sources.iterator().next().getClass());

            for (T source : sources) {
                Select select = new Select(invokeGetter(source,propertyDescriptorMap.get(valueFieldName)),invokeGetter(source,propertyDescriptorMap.get(labelFieldName)));
                if(source instanceof BaseEntity){

                    sort = true;

                    BaseEntity baseEntity = (BaseEntity)source;
                    Integer weight = baseEntity.getWeight();
                    if(StringUtils.isNotNull(weight))
                        select.setWeight(baseEntity.getWeight());

                }

                if(fill){
                    select.setData(source);
                }

                selectList.add(select);
            }
            if(sort){
                selectList.sort(Comparator.comparing(Select::getWeight).reversed());
            }
        }

        return selectList;
    }

    /**
     * 构建selectList 供前端 select选择器统一使用 默认不填充data
     * @param sources 源对象集合
     * @param valueSFunction value属性
     * @param labelSFunction lable属性
     * @param <T>
     * @return
     */
    public static <T> List<Select> buildSelectList(Collection<T> sources, SFunction<T,? extends Serializable> valueSFunction, SFunction<T,? extends Serializable> labelSFunction){

        return buildSelectList(sources,valueSFunction,labelSFunction,false);
    }

    /**
     * 构建selectList 供前端 select选择器统一使用 默认不填充data
     * @param sources 源对象集合
     * @param valueSFunction 即是 value 属性 又是 label 属性
     * @param <T>
     * @return
     */
    public static <T> List<Select> buildSelectList(Collection<T> sources, SFunction<T,? extends Serializable> valueSFunction){

        return buildSelectList(sources,valueSFunction,false);
    }

    /**
     * 构建selectList 供前端 select选择器统一使用 默认不填充data
     * @param sources 源对象集合
     * @param valueSFunction 即是 value 属性 又是 label 属性
     * @param fill 是否填充 默认不填充对象本身
     * @param <T>
     * @return
     */
    public static <T> List<Select> buildSelectList(Collection<T> sources, SFunction<T,? extends Serializable> valueSFunction,boolean fill){

        return buildSelectList(sources,valueSFunction,valueSFunction,fill);
    }

    /**
     * 执行 source方法 获取 参数值
     * @param source
     * @param propertyDescriptor
     * @param <T>
     * @return
     */
    private static <T> Serializable invokeGetter(T source, PropertyDescriptor propertyDescriptor) {
        /**在对象中找不到 这个属性*/
        if (propertyDescriptor==null) {
            throw new InteriorException(MessageFormat.format("obj:{} PropertyDescriptor is null ", source));
        }
        return ReflectUtils.invokeGetter(source, propertyDescriptor);
    }

}
